<?php
/**
 * FastApp.
 * 3/1/25
 * @Author deepsea
 * @Contact (telegram:deepsea159)
 */

namespace App\Hoenix\Api\Service;

use App\Fastapp\Api\Service\Telegram;
use App\Hoenix\Job\ConcubineKeywordJob;
use App\Hoenix\Model\HoenixConcubine;
use App\Hoenix\Model\HoenixConcubineOrder;
use Carbon\Carbon;
use Telegram\Bot\Api;
use Telegram\Bot\FileUpload\InputFile;

class TgConcubineBotService
{
    public static ?Api $cBot = null;

    public static function skipBotMessage(): bool
    {
        return true;
    }

    public static function handle(array $data, Api $bot, int $bot_id): void
    {
        if (isset($data['left_chat_member']) || $data['chat']['type'] != 'private') return;
        $account_type = redis()->hGet('bot:' . $bot_id, 'account_type');
        $uid = Telegram::getUid((string)$data['from']['id'], $account_type);
        if (!$uid) $uid = Telegram::createUser(array_merge($data['from'], ['type' => $account_type]));
        $message = '';
        $reply_markup = [];
        if (isset($data['entities'])) {
            list($cmds) = Telegram::parseEntity($data['entities'], $data['text']);
            if ($cmds[0]) self::cmd($cmds[0], $uid, $data['chat']['id'], $bot);
        } elseif ($param = get_user_cache('step', $uid)) {
            $res = self::upData($param, $data, $uid, $bot, $bot_id);
            if ($res) list($message, $reply_markup) = $res;
        }

        $send = self::getMessage($message, $reply_markup, $data['chat']['id']);
        if ($send) $bot->sendMessage($send);
    }

    public static function getStepTmp(string $param = '', int $uid = 0): array
    {
        $message = '';
        $keyboard = [];
        switch ($param) {
            case 'init_1':
                $message = implode("\n", [
                    '<blockquote>欢迎使用，请完善你的资料~~</blockquote>',
//                '<tg-spoiler>test</tg-spoiler>',
                    '请输入花名'
                ]);
                $keyboard[] = [['text' => '下一步', 'callback_data' => 'init_2']];
                break;
            case 'init_2':
                $message = '请输入姓名';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_3':
                $message = '请输入年龄';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_4':
                $message = '请输入身高(CM)';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_5':
                $message = '请输入体重(KG)';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_6':
                $message = '请输入学历';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_7':
                $message = '请输入职业';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_8':
                $message = '请输入所在城市';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_9':
                $msg[] = '请输入自我介绍';
                $msg[] = '示例：<code>听话，顺从，偶尔接几次，能提供情绪价值</code>';
                $msg[] = '填写自己的优势，让金主更好的找到你~';
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_10':
                $msg[] = '请输入从事原因';
                $msg[] = '示例：<code>缺钱，找人陪</code>';
                $msg[] = '填写从事原因，让金主更好的找到你~';
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_11':
                $msg[] = '请输入对金主的期望';
                $msg[] = '示例：<code>不要太老，温柔点</code>';
                $msg[] = '填写期望，让金主更好的找到你~';
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_12':
                $msg[] = '请输入服务内容';
                $msg[] = '示例：<code>2300¥ 120分钟 2次</code>';
                $msg[] = '填写服务内容，让金主更好的找到你~';
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_13':
                $msg[] = '请输入联系方式';
                $msg[] = "示例：<code>微信: wxxxxx 电话: 13xxxx </code>";
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_14':
                $msg[] = '请输入你的雷点';
                $msg[] = '示例：<code>不接受跳弹等，虐待</code>';
                $msg[] = '填写雷点，让金主更好的找到你~';
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_15':
                $message = '请选择能否接受包养';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_16':
                $message = '请输入包养费/月';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_17':
                $message = '请输入包养费每月分几次';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_18':
                $message = '请输入包养每月陪伴天数';
                $keyboard[] = self::getStep($param);
                break;
            case 'init_19':
                $msg[] = '请输入经期';
                $msg[] = '示例：<code>7天/月底</code>';
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_20':
                $message = '请选择是否处';
                $keyboard[] = self::getStep($param, true, '是');
                break;
            case 'init_21':
                $message = '请选择罩杯';
                $keyboard[] = [
                    ['text' => 'A', 'callback_data' => 'init_21_A'],
                    ['text' => 'B', 'callback_data' => 'init_21_B'],
                    ['text' => 'C', 'callback_data' => 'init_21_C'],
                    ['text' => 'D', 'callback_data' => 'init_21_C'],
                ];
                $keyboard[] = [
                    ['text' => 'E', 'callback_data' => 'init_21_E'],
                    ['text' => 'F', 'callback_data' => 'init_21_F'],
                    ['text' => 'G', 'callback_data' => 'init_21_G'],
                    ['text' => 'H', 'callback_data' => 'init_21_H'],
                ];
                break;
            case 'init_22':
                $message = '请选择能否口';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_23':
                $message = '请选择能否无套';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_24':
                $message = '请选择能否内';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_25':
                $message = '请选择能有无文身';
                $keyboard[] = [
                    ['text' => '无', 'callback_data' => 'init_25_0'],
                    ['text' => '有', 'callback_data' => 'init_25_1'],
                    ['text' => '极少', 'callback_data' => 'init_25_2'],
                ];
                break;
            case 'init_26':
                $message = '请选择能否同居';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_27':
                $message = '请选择能否过夜';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_28':
                $message = '请选择能否全国可飞';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_29':
                $message = '请选择能否外地';
                $keyboard[] = self::getStep($param, true);
                break;
            case 'init_30':
                $message = '请选择能否SM';
                $keyboard[] = [
                    ['text' => '否', 'callback_data' => 'init_30_0'],
                    ['text' => '能', 'callback_data' => 'init_30_1'],
                    ['text' => '轻微', 'callback_data' => 'init_30_2'],
                ];
                break;
            case 'init_31':
                $msg[] = '请输入出发时间';
                $msg[] = '示例：<code>随时、需要商议</code>';
                $msg[] = '填写出发时间，让金主更好的找到你~';
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_32':
                $msg[] = '请上传图片(提示：最新上传5张图片有效)';
                if ($uid) {
                    $img = HoenixConcubine::query()->where(['user_id' => $uid])->value('image');
                    if ($img) $msg[] = '已上传' . count($img) . '张图片';
                }
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param);
                break;
            case 'init_33':
                $msg[] = '请上传视频(提示：最新上传5个有效,请勿超过18M)';
                if ($uid) {
                    $img = HoenixConcubine::query()->where(['user_id' => $uid])->value('image');
                    if ($img) $msg[] = '已上传' . count($img) . '视频';
                }
                $message = implode("\n", $msg);
                $keyboard[] = self::getStep($param, last: true);
                break;
        }
        @list(, $step) = explode('_', $param);
        return [$message, $keyboard ? ['inline_keyboard' => $keyboard] : [], $step > 15 && $step != 19];
    }

    public static function upData(string $param, array $data, int $uid, Api $bot, int $bot_id): ?array
    {
        @list($prefix, $step, $select) = explode('_', $param);
        $next_step = (int)$step + 1;
        $next_cmd = implode('_', [$prefix, $next_step]);
        set_user_cache(['step' => 'init_' . $next_step], $uid);
        $up = [];
        if ($step == 1) $up['nickname'] = $data['text'];
        elseif ($step == 2) $up['name'] = $data['text'];
        elseif ($step == 3) $up['birthday'] = Carbon::now()->subYears((int)$data['text'])->format('Y-m') . '-01';
        elseif ($step == 4) $up['height'] = $data['text'];
        elseif ($step == 5) $up['weight'] = $data['text'];
        elseif ($step == 6) $up['qualification'] = $data['text'];
        elseif ($step == 7) $up['work'] = $data['text'];
        elseif ($step == 8) $up['city'] = $data['text'];
        elseif ($step == 9) $up['self_intro'] = $data['text'];
        elseif ($step == 10) $up['reason'] = $data['text'];
        elseif ($step == 11) $up['hope'] = $data['text'];
        elseif ($step == 12) $up['service'] = $data['text'];
        elseif ($step == 13) $up['remark'] = $data['text'];
        elseif ($step == 14) $up['trigger_point'] = $data['text'];
        elseif ($step == 15) {
            $up['type'] = $select;
            if (!$select) {
                $next_cmd = 'init_21';
                set_user_cache(['step' => $next_cmd], $uid);
            }
        } elseif ($step == 16) $up['wages'] = $data['text'];
        elseif ($step == 17) $up['wages_times'] = $data['text'];
        elseif ($step == 18) $up['accompany_day'] = $data['text'];
        elseif ($step == 19) $up['menstrual_period'] = $data['text'];
        elseif ($step == 20) $up['virgin'] = $select;
        elseif ($step == 21) $up['cup'] = $select;
        elseif ($step == 22) $up['oral_sex'] = $select;
        elseif ($step == 23) $up['condom'] = $select;
        elseif ($step == 24) $up['injection'] = $select;
        elseif ($step == 25) $up['tattoo'] = $select;
        elseif ($step == 26) $up['cohabitation'] = $select;
        elseif ($step == 27) $up['make_love'] = $select;
        elseif ($step == 28) $up['flyable'] = $select;
        elseif ($step == 29) $up['other_places'] = $select;
        elseif ($step == 30) $up['sm'] = $select;
        elseif ($step == 31) $up['on_duty'] = $data['text'];
        elseif ($step == 32 || $step == 33) {
            $field = $file_id = '';
            if (isset($data['photo'])) {
                $field = 'image';
                set_user_cache(['step' => 'init_32'], $uid);
                $file_id = end($data['photo'])['file_id'];
            }
            if (isset($data['video'])) {
                set_user_cache(['step' => 'init_33'], $uid);
                $field = 'video';
                $file_id = $data['video']['file_id'];
            }
            if (!$field) {
                $bot->sendMessage([
                    'chat_id' => $data['chat']['id'],
                    'text' => '请上传有效的资源',
                ]);
                return null;
            }
            $up[$field] = [];
            $n = 0;
            img:
            if (user_lock($uid)) {
                $md = HoenixConcubine::query()->firstOrCreate(['user_id' => $uid]);
                $up[$field] = $md[$field] ?: [];
                $up[$field][] = $file_id;
                $num = count($up[$field]);
                if ($num > 5) {
                    array_pop($up[$field]);
                    $num = 5;
                }
                if ($field == 'image') {
                    $message = "已上传{$num}张图片";
                    $keyboard[] = self::getStep($param);
                } else {
                    $message = "已上传{$num}个视频";
                    $keyboard[] = [['text' => '查看资料', 'callback_data' => '/info']];
                }
                $md->fill($up)->save();
                $bot->sendMessage([
                    'chat_id' => $data['chat']['id'],
                    'text' => $message,
                    'reply_markup' => json_encode(['inline_keyboard' => $keyboard], JSON_UNESCAPED_UNICODE),
                ]);
                user_unlock($uid);
            } else {
                $n++;
                if ($n > 10) {
                    \swoole\Coroutine::sleep(0.5);
                    goto img;
                }
            }
            $n = 0;
            store:
            if (user_lock($uid)) {
                $base = BASE_PATH . '/public/' . env('UPLOAD_PATH');
                $dir = '/hoenix/' . time();
                $rel_path = '';
                $t = 0;
                while (!$rel_path) {
                    try {
                        $rel_path = $bot->downloadFile($file_id, $base . $dir);
                    } catch (\Throwable) {
                        $t++;
                        if ($t > 2) return null;
                    }
                }
                $url = get_file_url(str_replace($base, '', $rel_path));
                $botConfig = redis()->hMGet('bot:' . $bot_id, ['robot_id', 'account_type']);
                $app_chat_media = (int)api_cache()->getAppSetting($botConfig['account_type'])['app_chat_media'];
                if ($field == 'image') {
                    $res = self::getCBot($botConfig['robot_id'])->sendPhoto([
                        'chat_id' => $app_chat_media,
                        'photo' => InputFile::create($url),
                    ])->toArray();
                    $new_file_id = end($res['photo'])['file_id'];
                } else {
                    $res = self::getCBot($botConfig['robot_id'])->sendVideo([
                        'chat_id' => $app_chat_media,
                        'video' => InputFile::create($url),
                    ])->toArray();
                    $new_file_id = $res['video']['file_id'];
                }
                $md = HoenixConcubine::query()->firstOrCreate(['user_id' => $uid]);
                $f = $field . 't';
                $tranStore[$f] = $md[$f] ?: [];
                $tranStore[$f][] = $new_file_id;
                if (count($tranStore[$f]) > 5) array_pop($tranStore[$f]);
                $md->fill($tranStore)->save();
                user_unlock($uid);
                @unlink($rel_path);
                @rmdir($base . $dir);
            } else {
                $n++;
                if ($n > 15) return null;
                \swoole\Coroutine::sleep(1);
                goto store;
            }
            return null;
        } else {
            self::cmd('/info', $uid, $data['chat']['id'], $bot);
            return null;
        }
        $md = HoenixConcubine::query()->firstOrCreate(['user_id' => $uid]);
        $md->fill($up)->save();
        return self::getStepTmp($next_cmd);
    }

    public static function cmd(string $cmd, int $uid, int $chat_id, Api $bot): void
    {
        $message = '';
        $reply_markup = [];
        if ($cmd == '/start') {
            list($message, $reply_markup) = self::getStepTmp('init_1');
            set_user_cache(['step' => 'init_1'], $uid);
        }
        if ($cmd == '/info') {
            set_user_cache(['step' => ''], $uid);
            $md = HoenixConcubine::query()->where(['user_id' => $uid])->first();
            list($message, $media) = self::formatInfo($md);
            if ($media) $bot->sendMediaGroup([
                'chat_id' => $chat_id,
                'media' => json_encode($media, JSON_UNESCAPED_UNICODE),
            ]);
            $reply_markup = [
                'inline_keyboard' => [
                    [
                        ['text' => '重新填写', 'callback_data' => '/start'],
                    ]
                ]
            ];
        }
        $send = self::getMessage($message, $reply_markup, $chat_id);
        if ($send) $bot->sendMessage($send);
    }

    public static function callbackQuery(array $data, Api $bot, int $bot_id): void
    {
        $res = redis()->hMGet('bot:' . $bot_id, ['account_type', 'robot_id']);
        $uid = Telegram::getUid((string)$data['from']['id'], $res['account_type']);
        if (!$uid) return;
        if (str_starts_with($data['data'], '/')) {
            self::cmd($data['data'], $uid, $data['message']['chat']['id'], $bot);
            if ($data['data'] == '/info') fastapp_queue_push(new ConcubineKeywordJob($uid, true), 'hoenix');
        } elseif (str_starts_with($data['data'], 'order')) {
            list(, $yes, $order_id) = explode('_', $data['data']);
            $md = HoenixConcubineOrder::query()->with(['concubine'])->where(['id' => $order_id, 'accept' => 0])->first();
            if (!$md) return;
            if ($md->update(['accept' => $yes == 'y' ? 1 : 2])) {
                if ($yes == 'y') {
                    $bot->editMessageText([
                        'chat_id' => $data['message']['chat']['id'],
                        'message_id' => $data['message']['message_id'],
                        'parse_mode' => 'HTML',
                        'text' => $data['message']['text'] . "\n===已接单 联系方式已同步客户===",
                    ]);
                    self::getCBot($res['robot_id'])->sendMessage([
                        'chat_id' => (int)get_user_cache('tgid', $md->user_id),
                        'parse_mode' => 'HTML',
                        'text' => implode("\n", [
                            '===服务人员已接单===',
                            '',
                            '下单时间：' . $md->created_at->toDateTimeString(),
                            '接单时间：' . $md->updated_at->toDateTimeString(),
                            '花名： <code>' . $md->concubine->nickname . '</code>',
                            '姓名： <code>' . $md->concubine->name . '</code>',
                            '联系方式：<code>' . $md->concubine->remark . '</code>',
                            '',
                            '=====祝你玩的愉快===='
                        ])
                    ]);
                } else {
                    $bot->editMessageText([
                        'chat_id' => $data['message']['chat']['id'],
                        'message_id' => $data['message']['message_id'],
                        'parse_mode' => 'HTML',
                        'text' => $data['message']['text'] . "\n===已拒单===",
                    ]);
                    self::getCBot($res['robot_id'])->sendMessage([
                        'chat_id' => (int)get_user_cache('tgid', $md->user_id),
                        'parse_mode' => 'HTML',
                        'text' => implode("\n", [
                            '===服务人员已拒单===',
                            '',
                            '下单时间：' . $md->created_at->toDateTimeString(),
                            '拒单时间：' . $md->updated_at->toDateTimeString(),
                            '花名： <code>' . $md->concubine->nickname . '</code>',
                            '姓名： <code>' . $md->concubine->name . '</code>',
                            '',
                            '=====请重新挑选服务人员===='
                        ])
                    ]);
                }
            }
        } else {
            if (substr_count($data['data'], '_') > 1) $res = self::upData($data['data'], $data, $uid, $bot, $bot_id);
            else {
                set_user_cache(['step' => $data['data']], $uid);
                $res = self::getStepTmp($data['data']);
            }
            if (!$res) return;
            @list($message, $reply_markup, $edit) = $res;
            $send = self::getMessage($message, $reply_markup, $data['message']['chat']['id']);
            if (!$send) return;
            if ($edit) {
                $send['message_id'] = $data['message']['message_id'];
                $bot->editMessageText($send);
            } else $bot->sendMessage($send);
        }
    }

    public static function guide(int $chat_id, array $name, Api $bot, int $bot_id): void
    {
        $msg = '欢迎';
        foreach ($name as $id => $v) {
            $msg .= "<a href=\"tg://user?id=$id\">$v </a>";
        }
        $message = [
            $msg,
            '加入群组！',
            "\n",
            '<a href="',
            redis()->hGet('bot:' . $bot_id, 'link'),
            '?start=init">点击这里填写信息>></a>'
        ];
        $send = self::getMessage(implode('', $message), [], $chat_id);
        if ($send) $bot->sendMessage($send);
    }

    public static function getMessage(string $message, array $reply_markup, int $chat_id, int $reply_to_message_id = 0): array
    {
        if ($message || $reply_markup) {
            $parameters = [
                'chat_id' => $chat_id,
                'parse_mode' => 'HTML',
            ];
            if ($reply_to_message_id) $parameters['reply_to_message_id'] = $reply_to_message_id;
            if ($message) $parameters['text'] = $message;
            if ($reply_markup) $parameters['reply_markup'] = json_encode($reply_markup, JSON_UNESCAPED_UNICODE);
            return $parameters;
        }
        return [];
    }

    public static function getStep(string $cmd, bool $select = false, string $yes = '能', bool $last = false): array
    {
        if ($select) return [
            ['text' => $yes, 'callback_data' => $cmd . '_1'],
            ['text' => '否', 'callback_data' => $cmd . '_0'],
        ];
        list($cmd, $step) = explode('_', $cmd);
        if ($last) $end = ['text' => '查看资料', 'callback_data' => '/info'];
        else $end = ['text' => '下一步', 'callback_data' => implode('_', [$cmd, (int)$step + 1])];
        return [
            ['text' => '上一步', 'callback_data' => implode('_', [$cmd, (int)$step - 1])],
            $end
        ];
    }

    public static function formatInfo(HoenixConcubine $md, int $type = 0): array
    {
        $msg = [
            '花名: ' . $md->nickname,
            '姓名: ' . $md->name,
            '年龄: ' . Carbon::now()->diff($md->birthday)->y,
            '身高: ' . $md->height . '(CM)',
            '体重: ' . $md->weight . '(KG)',
            '罩杯: ' . $md->cup,
            '学历: ' . $md->qualification,
            '职业: ' . $md->work,
            '城市: ' . $md->city,
            '能否口: ' . ($md->oral_sex ? '能' : '否'),
            '能否无: ' . ($md->condom ? '能' : '否'),
            '能否内: ' . ($md->injection ? '能' : '否'),
            '文身: ' . ($md->tattoo ? '有' : '无'),
            '可飞: ' . ($md->flyable ? '能' : '否'),
            '能否外地: ' . ($md->other_places ? '能' : '否'),
            '出发时间: ' . ($md->on_duty ?: '-'),
        ];
        if ($md->trigger_point) $msg[] = '雷点：' . $md->trigger_point;
        if ($md->type) {
            $msg[] = '能否包养：' . ($md->type ? '能' : '否');
            $msg[] = '经期：' . $md->menstrual_period;
            $msg[] = '陪伴天数：' . $md->accompany_day;
            $msg[] = '期望/月：' . $md->wages . '¥';
            $msg[] = '分次/月：' . $md->wages_times;
        }
        if ($md->reason) $msg[] = '从事原因：' . $md->reason;
        if ($md->self_intro) $msg[] = '自我介绍：' . $md->self_intro;
        if ($md->hope) $msg[] = '对金主希望：' . $md->hope;
        if ($md->service) $msg[] = '服务内容：' . $md->service;
        $msg[] = '认证时间: ' . ($md->certified_at ?: '未认证');
        $media = [];
        foreach (($type ? $md->imaget : $md->image) ?? [] as $file_id) $media[] = ['type' => 'photo', 'media' => $file_id];
        foreach (($type ? $md->videot : $md->video) ?? [] as $file_id) $media[] = ['type' => 'video', 'media' => $file_id];
        return [implode("\n", $msg), $media];
    }

    public static function getCBot(int|string $bot_id): Api
    {
        if (self::$cBot) return self::$cBot;
        self::$cBot = new Api(redis()->hGet('bot:' . $bot_id, 'token'));
        return self::$cBot;
    }

    public static function init(Api $bot): void
    {
        $bot->deleteMyCommands();
        $commands = [
            ['command' => 'start', 'description' => '完善资料'],
            ['command' => 'info', 'description' => '我的资料'],
            ['command' => 'set_order', 'description' => '设置是否接单'],
        ];
        $bot->setMyCommands(['commands' => $commands]);
    }
}